import { message } from "antd";
import { ApiError, httpClient } from "./httpClient";

export const errorHandler = (error: ApiError | any) => {
  if (error.code == -1) {
    message.error(error.msg);
  }
};
export const HearderType = ["multipart/form-data;"];

export async function getOptionValueFromTable(
  tableName: string,
  param: object,
  col: string[]
) {
  param = { ...param };
  const res = await httpClient.get(`/admin/${tableName}/lists`, param);
  return (res?.items || []).map((item: any) => {
    // 构建扩展属性对象，包含第三个及之后的所有列
    const extendsObj: Record<string, any> = {};
    for (let i = 2; i < col.length; i++) {
      extendsObj[col[i]] = item[col[i]];
    }

    return {
      value: item[col[0]],
      label: item[col[1]],
      ...extendsObj,
    };
  });
}
export const ToChartSeries = (name: string, type: string, data: []) => {
  return {
    name,
    type,
    yAxisIndex: 0,
    data,
    lineStyle: {
      width: 1,
    },
    emphasis: {
      focus: "series",
    },
    areaStyle: {
      opacity: 0.3,
    },
    smooth: true,
    symbol: "none",
  };
};
/**
 * 根据指定键对对象数组进行分组，并提取指定键的值到列表中
 * @param array 待分组的对象数组
 * @param groupKey 用于分组的属性名
 * @param valueKey 用于提取值的属性名
 * @returns 分组后的数组，格式为 [{ name: 分组键值, lists: 值数组 }]
 */
export function GroupBy<
  T extends Record<string, any>,
  K extends keyof T,
  V extends keyof T,
>(array: T[], groupKey: K, valueKey: V): { name: T[K]; lists: T[V][] }[] {
  // 使用 Map 来存储分组结果，键是分组键的值，值是值键的数组
  const groupedMap = array.reduce((map, currentItem) => {
    // 获取当前项的分组键值
    const key = currentItem[groupKey];
    // 获取当前项的值键值
    const value = currentItem[valueKey];

    // 如果 Map 中还没有该分组键，则初始化一个空数组
    if (!map.has(key)) {
      map.set(key, []);
    }

    // 将当前项的值键值添加到对应的分组数组中
    map.get(key)!.push(value);

    return map;
  }, new Map<T[K], T[V][]>()); // 初始化为一个空的 Map

  // 将 Map 转换为所需的数组格式
  const result: { name: T[K]; lists: T[V][] }[] = [];
  groupedMap.forEach((lists, name) => {
    result.push({ name, lists });
  });

  return result;
}

/**
 * 获取数组中指定键的最大值、最小值及对应的数据项
 * @param arr 数据数组
 * @param key 用于比较的键名
 * @returns 包含 min, max, minData, maxData 的对象
 */
export function GetMinMaxByKey(
  arr: any[],
  key: string
): {
  min: number;
  max: number;
  minData: any;
  maxData: any;
} {
  // 边界情况：数组为空
  if (!arr || arr.length === 0) {
    return { min: 0, max: 0, minData: {}, maxData: {} };
  }

  // 过滤掉无效值（非数字）
  const validItems = arr.filter((item: any) => {
    const value = item[key];
    return typeof value === "number" && !isNaN(value);
  });

  // 如果没有有效的数字
  if (validItems.length === 0) {
    return { min: 0, max: 0, minData: {}, maxData: {} };
  }

  // 查找最小值和最大值及其对应的数据项
  let minItem = validItems[0];
  let maxItem = validItems[0];
  let minValue = minItem[key];
  let maxValue = maxItem[key];

  for (const item of validItems) {
    const value = item[key];
    if (value < minValue) {
      minValue = value;
      minItem = item;
    }
    if (value > maxValue) {
      maxValue = value;
      maxItem = item;
    }
  }

  return {
    min: minValue,
    max: maxValue,
    minData: minItem,
    maxData: maxItem,
  };
}
export function DateformatDate(
  dateInput: string | Date = new Date(),
  format: string = "YYYY-MM-DD"
): string {
  // 统一处理输入参数，确保其为 Date 对象
  const date = typeof dateInput === "string" ? new Date(dateInput) : dateInput;
  // 检查日期有效性
  if (isNaN(date.getTime())) {
    throw new Error("Invalid date string provided");
  }

  // 定义占位符映射对象，使用 padStart 确保两位数格式[7](@ref)
  const formatMap: { [key: string]: string } = {
    YYYY: date.getFullYear().toString(),
    YY: date.getFullYear().toString().slice(-2),
    MM: (date.getMonth() + 1).toString().padStart(2, "0"), // 月份从0开始[2](@ref)
    DD: date.getDate().toString().padStart(2, "0"),
    HH: date.getHours().toString().padStart(2, "0"),
    mm: date.getMinutes().toString().padStart(2, "0"),
    ss: date.getSeconds().toString().padStart(2, "0"),
  };

  // 使用正则表达式替换所有占位符[7](@ref)
  return format.replace(/YYYY|YY|MM|DD|HH|mm|ss/g, (match) => formatMap[match]);
}
export function SplitWeekString(weekStr: string) {
  // 1. 解析字符串：使用正则表达式提取年份和周数 [1,6](@ref)
  const matches = weekStr.match(/^(\d{4})-(\d+)th$/);
  if (!matches) {
    throw new Error('无效格式，应为 "YYYY-WWth"（例如 "2025-40th"）');
  }
  const year = parseInt(matches[1]);
  const week = parseInt(matches[2]);

  // 2. 计算周范围：基于 ISO 周日期系统（周一为起始）[3,4](@ref)
  // 找到该年1月4日（ISO 第一周包含此日期）
  const jan4 = new Date(year, 0, 4);
  const jan4Day = jan4.getDay(); // 获取星期几（0=周日, 1=周一, ..., 6=周六）

  // 计算第一周的周一：1月4日减去偏移量（偏移量 = jan4Day === 0 ? 6 : jan4Day - 1）
  const startOfFirstWeek = new Date(jan4);
  const offset = jan4Day === 0 ? 6 : jan4Day - 1;
  startOfFirstWeek.setDate(jan4.getDate() - offset);

  // 计算目标周的周一：第一周的周一 + (周数 - 1) * 7天
  const weekStart = new Date(startOfFirstWeek);
  weekStart.setDate(startOfFirstWeek.getDate() + (week - 1) * 7);

  // 计算目标周的周日：周一 + 6天
  const weekEnd = new Date(weekStart);
  weekEnd.setDate(weekStart.getDate() + 6);

  // 3. 格式化日期：转换为 "YYYY-MM-DD" 格式 [3,7](@ref)
  function formatDate(date: Date) {
    const y = date.getFullYear();
    const m = (date.getMonth() + 1).toString().padStart(2, "0"); // 月份从0开始，需+1
    const d = date.getDate().toString().padStart(2, "0");
    return `${y}-${m}-${d}`;
  }

  return {
    start: formatDate(weekStart),
    end: formatDate(weekEnd),
  };
}
export function GetWeekRange(dateString: string) {
  // 1. 将输入的字符串转换为 Date 对象
  const givenDate = new Date(dateString);

  // 2. 获取给定日期是星期几 (0 代表周日, 1 代表周一, ..., 6 代表周六)
  const dayOfWeek = givenDate.getDay();

  // 3. 计算本周一的日期
  const startOfWeek = new Date(givenDate);
  // 核心计算逻辑：如果当天是周日(0)，需要减去6天到上周一；否则减去 (dayOfWeek - 1) 天到本周一
  const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
  startOfWeek.setDate(givenDate.getDate() + mondayOffset);

  // 4. 计算本周日的日期（周一 + 6天）
  const endOfWeek = new Date(startOfWeek);
  endOfWeek.setDate(startOfWeek.getDate() + 6);

  // 5. 格式化日期为 'YYYY-MM-DD'
  function formatDate(date: Date) {
    return date.toISOString().split("T")[0];
  }

  return {
    start: formatDate(startOfWeek), // 本周一的日期
    end: formatDate(endOfWeek), // 本周日的日期
  };
}
export function GetISOWeeksNumber(dateString: string) {
  const date = new Date(dateString);

  // 1. 找到给定日期所在周的星期四
  const thursday = new Date(date);
  // 调整到本周的星期四：当前日期 + (4 - 当前星期几)
  // 如果getDay()返回0（周日），则使用7进行计算
  thursday.setDate(date.getDate() + 4 - (date.getDay() || 7));

  // 2. 获取该星期四的年份，作为ISO年份
  const isoYear = thursday.getFullYear();

  // 3. 计算该年的1月1日
  const yearStart = new Date(isoYear, 0, 1); // 月份0代表1月

  // 4. 计算从年初到该星期四经过的完整天数
  const daysDiff =
    (thursday.getTime() - yearStart.getTime()) / (24 * 60 * 60 * 1000);

  // 5. 计算周数：天数差 + 1（因为1月1日是第1天），然后除以7并向上取整
  const weekNumber = Math.ceil((daysDiff + 1) / 7);

  // 6. 格式化输出为 "YYYY-WWth"
  return `${isoYear}-${weekNumber}th`;
}
export function GetLastDayOfMonthFormatted(dateString: string) {
  const date = new Date(dateString);
  const year = date.getFullYear();
  const month = date.getMonth();

  const lastDay = new Date(year, month + 1, 0);

  // 格式化输出为 YYYY-MM-DD
  const formattedYear = lastDay.getFullYear();
  const formattedMonth = String(lastDay.getMonth() + 1).padStart(2, "0"); // 月份加1并补零
  const formattedDate = String(lastDay.getDate()).padStart(2, "0");

  return `${formattedYear}-${formattedMonth}-${formattedDate}`;
}
export function FormatDateToQuarter(dateStr: string) {
  const date = new Date(dateStr);
  const year = date.getFullYear();
  const month = date.getMonth() + 1; // getMonth()返回0-11，需加1

  const quarter = Math.ceil(month / 3);
  return `${year}-Q${quarter}`;
}
interface TreeNode<T = any> {
  children?: TreeNode<T>[];
  [key: string]: any; // 或者根据实际需求做更严格的限制
}
export function ArrayToTree<T extends Record<string, any>>(
  data: T[],
  options: { idKey?: string; parentKey?: string; childrenKey?: string } = {},
  parentId: any = 0
): TreeNode<T>[] {
  const {
    idKey = "id",
    parentKey = "parentId",
    childrenKey = "children",
  } = options;

  if (!Array.isArray(data)) {
    return [];
  }

  const children = data.filter((item) => item[parentKey] === parentId);
  return children.map((item) => ({
    ...item,
    [childrenKey]: ArrayToTree(data, options, item[idKey]),
  }));
}
//递归找到 某个字段在拼接
export const FindPathFromKey = (
  trees: [],
  key: string,
  childName: string = "child",
  valueArr: [] = []
) => {
  trees.forEach((tree) => {
    if (tree[key] && typeof tree[key] == "object") {
      (tree[key] as []).forEach((v) => {
        valueArr.push(v);
      });
      if (tree[childName]) {
        FindPathFromKey(tree[childName], key, childName, valueArr);
      }
    }
  });
  return valueArr;
};
